package com.ruoyi.business.task;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.bizsys.domain.*;
import com.ruoyi.bizsys.service.*;
import com.ruoyi.common.enums.UserTagEnum;
import com.ruoyi.common.utils.Func;
import com.ruoyi.common.utils.ObjectUtil;
import com.ruoyi.common.utils.StringUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Author: ygw
 * @Date: 2022/04/22/18:34
 * @Description:
 */

@Slf4j
@RestController
@RequestMapping("/retry/")
@AllArgsConstructor
public class UpdataAppUsetTagInitTask {


    private IAppUserService userService;

    private IRealNameAuthService realNameAuthService;

    private IRealNameAuthLogService realNameAuthLogService;

    private ICreditAccountService creditAccountService;

    private ICreditApplyService creditApplyService;

    private ILoanOrderService loanOrderService;

    private IIncreasedLimitLogService increasedLimitLogService;

    private IAppUserMarkService appUserMarkService;

    private ICustomerInfoService customerInfoService;

    private ICustBankCardService custBankCardService;

    private IBankAccountService bankAccountService;

    public static String TRANSFER_NOT_FOUND = "{\"message\":\"Transfer not found\",\"status\":false}";
    public static String ERROR_OCCURRED = "Error Occurred";
    public static String CANNOT_INITIATE = "You cannot initiate third party payouts at this time";


    @PostMapping("updataRunTask")
    public void updataRunTask() {

        int coreSize = 4;
        int threadExcSize = 1000;
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(coreSize, coreSize, 0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>());

        List<AppUser> userAll = userService.list(new QueryWrapper<AppUser>().select("user_uuid", "password", "phone"));

        int size = (userAll.size() / threadExcSize) + 1;
        List<List<AppUser>> lists = ObjectUtil.averageAssign(userAll, size);
        Semaphore semaphore = new Semaphore(coreSize);
        //每条线程每次处理约500个用户
        for (List<AppUser> userList : lists) {

            try {
                semaphore.acquire();
                threadPoolExecutor.execute(new UserTagTask(userList, semaphore));
            } catch (InterruptedException e) {
                log.error("thread执行异常", e);
            }
        }

        //初始化安装未注册标签
        List<String> phoneList = userService.selectUnRegisterUserList();
        if (phoneList.size()>0) {
            //查询appUserMark
            List<AppUserMark> appUserMarks = appUserMarkService.list();
            try {
                List<AppUserMark> appUserMarkList = new ArrayList<>();
                phoneList.forEach(e -> appUserMarkList.add(AppUserMark.builder().registerPhone(e)
                        .firstTag(UserTagEnum.UN_REGISTERED.getFirstTag())
                        .createTime(new Date()).updateTime(new Date())
                        .build()));

                //判断数据是否存在

                List<AppUserMark> updataAppUserMarks = new ArrayList<>();
                List<AppUserMark> insertAppUserMarks = new ArrayList<>();
                for (int i = 0; i < appUserMarkList.size(); i++) {
                    for (int j = 0; j < appUserMarks.size(); j++) {
                        if (appUserMarkList.get(i).getRegisterPhone().equals(appUserMarks.get(j).getRegisterPhone())) {
                            //满足则修改
                            appUserMarkList.get(i).setId(appUserMarks.get(j).getId());
                            updataAppUserMarks.add(appUserMarkList.get(i));
                        }
                    }
                    insertAppUserMarks.add(appUserMarkList.get(i));
                }
                //去重
                Collection exists =new ArrayList<AppUserMark>(insertAppUserMarks);
                exists.removeAll(updataAppUserMarks);
                appUserMarkService.insertBatch((List<AppUserMark>) exists);

                if(updataAppUserMarks.size()>0){
                    appUserMarkService.updateBatchById(updataAppUserMarks);
                }
            } catch (Exception e) {
                log.error("Run 安装未注册标签 异常", e);
            } finally {
                semaphore.release();
            }
            threadPoolExecutor.shutdown();

        }
    }

    private class UserTagTask implements Runnable {

        private List<AppUser> userList;

        private Semaphore semaphore;

        UserTagTask(List<AppUser> userList, Semaphore semaphore) {
            this.userList = userList;
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            try {
                List<AppUserMark> appUserMarkList = new ArrayList<>();
                //查询appUserMark
                List<AppUserMark> appUserMarks = appUserMarkService.list();
                userList.forEach(e -> {
                    appUserMarkList.add(new UserDetail(e).getUserTagEnum());
                });
                log.info("appUserMarkList:"+appUserMarkList.size());

                List<AppUserMark> updataAppUserMarks = new ArrayList<>();
                List<AppUserMark> insertAppUserMarks = new ArrayList<>();
                for (int i = 0; i < appUserMarkList.size(); i++) {
                    for (int j = 0; j < appUserMarks.size(); j++) {
                        if (appUserMarkList.get(i).getRegisterPhone().equals(appUserMarks.get(j).getRegisterPhone())) {
                            //满足则修改
                            appUserMarkList.get(i).setId(appUserMarks.get(j).getId());
                            updataAppUserMarks.add(appUserMarkList.get(i));
                        }
                    }
                    insertAppUserMarks.add(appUserMarkList.get(i));
                }
                //去重
                Collection exists =new ArrayList<AppUserMark>(insertAppUserMarks);
                exists.removeAll(updataAppUserMarks);
                appUserMarkService.insertBatch((List<AppUserMark>) exists);

                if(updataAppUserMarks.size()>0){
                    appUserMarkService.updateBatchById(updataAppUserMarks);
                }
            } catch (Exception e) {
                log.error("Run异常", e);
            } finally {
                semaphore.release();
            }
        }
    }

    private class UserDetail {

        private AppUser user;

        private RealNameAuth realNameAuth;

        private CreditAccount creditAccount;

        private CustomerInfo customerInfo;

        UserDetail(AppUser appUser) {
            this.user = appUser;
        }

        public AppUserMark getUserTagEnum() {
            UserTagEnum tagEnum = getTagEnum();
            AppUserMark appUserMark = AppUserMark.builder().userId(user.getUserUuid()).build();
            appUserMark.setFirstTag(tagEnum.getFirstTag());
            appUserMark.setSecondTag(tagEnum.getSecondTag());
            appUserMark.setRegisterPhone(user.getPhone());
            if (Func.isNotEmpty(customerInfo)) {
                appUserMark.setCustNo(customerInfo.getCustNo());
            }
            if ("Identity verification failed".equals(tagEnum.getFirstTag())) {
                appUserMark.setRemark(tagEnum.getSecondTag());
            }
            if (Func.isNotEmpty(realNameAuth)) {
                appUserMark.setLastName(realNameAuth.getLastName());
                appUserMark.setBvnPhone(realNameAuth.getPhoneNumber());
                appUserMark.setBirthday(realNameAuth.getBirthDate());
                appUserMark.setGender(realNameAuth.getGender());
            }
            if (Func.isNotEmpty(creditAccount)) {
                appUserMark.setCreditLine(creditAccount.getCreditLine());
                appUserMark.setLoanQuota(creditAccount.getLoanQuota());
                IncreasedLimitLog increasedAmtByCust = increasedLimitLogService.getIncreasedAmtByCust(creditAccount.getCustNo());
                appUserMark.setIncreasedAmt(increasedAmtByCust.getIncreasedAmt());
                appUserMark.setIncreasedCreateTime(increasedAmtByCust.getCreateTime());
            }
            if ("Withdrawal failed".equals(tagEnum.getFirstTag())) {
                LoanOrder oneByCustNo = loanOrderService.getOneByCustNo(customerInfo.getCustNo());
                appUserMark.setRemark(oneByCustNo.getRemark());
            }
            Date date = new Date();
            appUserMark.setCreateTime(date);
            appUserMark.setUpdateTime(date);
            return appUserMark;
        }

        private UserTagEnum getTagEnum() {
            //注册 无密码
            customerInfo = customerInfoService.getOne(new QueryWrapper<CustomerInfo>().eq("user_id", user.getUserUuid()));
            if (Func.isEmpty(user.getPassword())) {
                return UserTagEnum.REGISTERED_NOT_PASSWORD;
            }
            RealNameAuth realNameAuth = realNameAuthService.getOne(new QueryWrapper<RealNameAuth>().eq("user_id", user.getUserUuid()));
            //未实名 -> 注册 有密码
            if (Func.isEmpty(realNameAuth)) {
                //是否实名失败
                QueryWrapper<RealNameAuthLog> logQueryWrapper = new QueryWrapper<RealNameAuthLog>().eq("user_id", user.getUserUuid()).last("order by id desc limit 1");
                RealNameAuthLog realNameAuthLog = realNameAuthLogService.getOne(logQueryWrapper);
                //如果没有实名 -> 注册 有密码
                if (Func.isEmpty(realNameAuthLog)) {
                    return UserTagEnum.REGISTERED_NOT_VERIFIED;
                }
                UserTagEnum userTagEnum = UserTagEnum.exceptionMapper(realNameAuthLog.getErrorMsg());
                return Optional.ofNullable(userTagEnum).orElse(UserTagEnum.getDiy("Identity verification failed", realNameAuthLog.getErrorMsg()));
            }
            this.realNameAuth = realNameAuth;

            //是否授信
            CreditApply creditApply = creditApplyService.getOne(new QueryWrapper<CreditApply>().eq("cust_no", realNameAuth.getCustNo()).last("order by id desc limit 1"));
            if (Func.isEmpty(creditApply)) {
                //没有授信 -> 实名成功
                return UserTagEnum.IDENTITY_VERIFIED_SUCCESS;
            }
            //没有授信 -> 授信失败
            if (1 != creditApply.getApplyStatus()) {
                //risk被拒
                if (0 == creditApply.getApplyStatus()) {
                    return UserTagEnum.CREDIT_APPLICATION_FAILED_RISK_REJECT;
                } else {
                    //系统原因
                    return UserTagEnum.CREDIT_APPLICATION_FAILED;
                }
            }
            this.creditAccount = creditAccountService.getOne(new QueryWrapper<CreditAccount>().eq("cust_no", realNameAuth.getCustNo()));

            LoanOrder loanOrder = loanOrderService.getOne(new QueryWrapper<LoanOrder>().eq("cust_no", realNameAuth.getCustNo()).last("order by id desc limit 1"));
            if (Func.isEmpty(loanOrder)) {
                //没有提现记录 -> 授信成功 有无Account
                if (bankAccountService.countByCustNo(realNameAuth.getUserId()) > 0) {
                    return UserTagEnum.CREDIT_APPLICATION_SUCCESS_ACCOUNT_EXISTED;
                } else {
                    return UserTagEnum.CREDIT_APPLICATION_SUCCESS_ACCOUNT_NOT_EXIST;
                }
            }

            if (0 == loanOrder.getLoanStatus()) {
                return UserTagEnum.LOAN_REJECT;
            }

            if (10 == loanOrder.getLoanStatus()) {
                return UserTagEnum.LOAN_FAILED;
            }
            if (5 == loanOrder.getLoanStatus() && StringUtils.equalsAny(loanOrder.getRemark(), TRANSFER_NOT_FOUND, ERROR_OCCURRED, CANNOT_INITIATE)) {
                return UserTagEnum.LOAN_FAILED;
            }

            if (4 == loanOrder.getLoanStatus()) {
                int cardCount = custBankCardService.count(new QueryWrapper<CustBankCard>().eq("cust_no", loanOrder.getCustNo()));
                return cardCount > 0 ? UserTagEnum.LOAN_SUCCEED_BIND_CARD : UserTagEnum.LOAN_SUCCEED_NOT_CARD;
            }
            return UserTagEnum.LOAN_FAILED;
        }
    }
}


